package cn.swpu.blog.filter;

import cn.swpu.blog.util.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.val;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author 冰翔
 * @Date 2021/2/19 22:06
 */
@Component
public class JwtFilter extends OncePerRequestFilter {

    private static final String HTTP_HEADER = "Authorization";
    private static final String HTTP_PREFIX = "Bearer ";

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {
        System.out.println(request.getRequestURI());
        if(checkJwtToken(request)){
            Optional<Claims> authorities = validateToken(request)
                    .filter(claims -> claims.get("authorities") != null);

            //有值
            if (authorities.isPresent()) {
                setupSpringAuthentication(authorities.get());
            //为空
            } else {
                SecurityContextHolder.clearContext();
            }

        }

        filterChain.doFilter(request, response);
    }

    private void setupSpringAuthentication(Claims claims) {
        val rawList = convertObjectToList(claims.get("authorities"));
        val authorities = rawList.stream()
                .map(String::valueOf)
                .map(SimpleGrantedAuthority::new)
                .collect(Collectors.toList());
        val authentication = new UsernamePasswordAuthenticationToken(claims.getSubject(), null, authorities);
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

    private Optional<Claims> validateToken(HttpServletRequest request) {
        //取出请求头中的token，并将前缀替换为空
        String jwtToken = request.getHeader(HTTP_HEADER).replace(HTTP_PREFIX, "");

        //解析并转化为Claims
        return Optional.of(Jwts.parser().setSigningKey(JwtUtil.KEY).parseClaimsJws(jwtToken).getBody());
    }

    /**
     * 检查JWT token 是否在HTTP报文头中
     * @param request HTTP请求
     * @return 是否有JWT Token
     */
    private boolean checkJwtToken(HttpServletRequest request) {
        String authenticationHeader = request.getHeader(HTTP_HEADER);
        return authenticationHeader != null && authenticationHeader.startsWith(HTTP_PREFIX);
    }

    /**
     * 将object转化为list 数组
     */
    private static List<?> convertObjectToList(Object obj) {
        List<?> list = new ArrayList<>();
        if (obj.getClass().isArray()) {
            list = Arrays.asList((Object[])obj);
        } else if (obj instanceof Collection) {
            list = new ArrayList<>((Collection<?>) obj);
        }
        return list;
    }
}
